package com.migration.model.migration.scripts;

import com.migration.model.migration.AbstractMultiThreadMigrationScript;
import com.migration.model.migration.CustomExecutableMigrationScript;
import com.migration.model.newdb.RiskChainConsequenceProtection;
import com.migration.model.newdb.RiskChainEffectProtection;
import com.migration.model.newdb.RiskChainEffectSuggestion;
import com.migration.model.olddb.RaAdviseMeasures;
import com.migration.model.olddb.RaDefendMeasures;
import com.migration.model.olddb.RaFaultChainsDetail;
import com.migration.model.olddb.RaFaultChainsMeasure;
import com.migration.service.RiskChainDetailService;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 事故链措施关系数据迁移脚本
 */
@Component
public class A027_RiskChainMigrationScript extends AbstractMultiThreadMigrationScript implements CustomExecutableMigrationScript {

    @Autowired
    @Qualifier("oldEntityManagerFactory")
    private EntityManagerFactory oldEntityManagerFactory;

    @Autowired
    @Qualifier("newEntityManagerFactory")
    private EntityManagerFactory newEntityManagerFactory;

    @Autowired
    private RiskChainDetailService riskChainDetailService;

    /**
     * 构造函数，初始化迁移配置
     */
    public A027_RiskChainMigrationScript() {
        super(
                "risk_chain_all",
                "事故链-措施关系数据迁移",
                "多表关联",
                "risk_chain_effect_protection",
                27
        );
    }

    @Override
    protected String generateMigrationSql() {
        return "";
    }

    @Override
    public int executeCustomMigration(DataSource dataSource) {
        // 清空目标表
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.execute(getTruncateSql());
        jdbcTemplate.execute("TRUNCATE TABLE risk_chain_consequence_protection;");
        jdbcTemplate.execute("TRUNCATE TABLE risk_chain_effect_suggestion;");

        // 执行自定义迁移
        return executeWithEntityProcessingMultiThread(oldEntityManagerFactory, newEntityManagerFactory);
    }

    protected int executeWithEntityProcessingMultiThread(EntityManagerFactory oldEntityManagerFactory, EntityManagerFactory newEntityManagerFactory) {
        EntityManager oldEntityManager = oldEntityManagerFactory.createEntityManager();
        AtomicInteger rowsProcessed = createAtomicCounter();

        try {
            // 1. 获取所有需要的数据
            // 获取所有事故链措施关系数据
            List<RaFaultChainsMeasure> measureList = riskChainDetailService.getAllFaultChainsMeasures(oldEntityManager);

            // 获取所有事故链详情数据
            List<RaFaultChainsDetail> detailList = riskChainDetailService.getAllFaultChainsDetails(oldEntityManager);

            // 构建detail ID 到 effect_id(influenceId)的映射
            Map<Long, Long> detailIdToInfluenceIdMap = new HashMap<>();
            for (RaFaultChainsDetail detail : detailList) {
                if (detail.getInfluenceId() != null) {
                    detailIdToInfluenceIdMap.put(detail.getId(), detail.getInfluenceId());
                }
            }

            // 构建detail ID 到 effect_id(influenceId的String形式)的映射
            Map<Long, String> detailIdToEffectIdMap = new HashMap<>();
            for (RaFaultChainsDetail detail : detailList) {
                if (detail.getInfluenceId() != null) {
                    detailIdToEffectIdMap.put(detail.getId(), detail.getInfluenceId().toString());
                }
            }

            // 构建detail ID 到 consequence_id的映射
            Map<Long, String> detailIdToConsequenceIdMap = new HashMap<>();
            for (RaFaultChainsDetail detail : detailList) {
                if (detail.getConsequenceId() != null) {
                    detailIdToConsequenceIdMap.put(detail.getId(), detail.getConsequenceId().toString());
                }
            }

            // 过滤出有效的措施关系数据
            List<RaFaultChainsMeasure> validMeasures = measureList.stream()
                    .filter(measure -> measure.getSourceType() != null
                                      && measure.getMeasuresType() != null
                                      && measure.getLinkedId() != null
                                      && measure.getMeasuresId() != null)
                    .collect(Collectors.toList());

            // 计算总批次数
            int totalBatches = calculateBatchCount(validMeasures.size());

            // 创建线程池和计数器
            ExecutorService executorService = createExecutorService();
            CountDownLatch latch = createCountDownLatch(totalBatches);

            // 按批次处理数据
            for (int i = 0; i < totalBatches; i++) {
                int fromIndex = i * batchSize;
                int toIndex = Math.min(fromIndex + batchSize, validMeasures.size());
                List<RaFaultChainsMeasure> measureBatch = validMeasures.subList(fromIndex, toIndex);

                executorService.submit(() -> {
                    try {
                        EntityManager newEntityManager = newEntityManagerFactory.createEntityManager();
                        try {
                            newEntityManager.getTransaction().begin();

                            int batchProcessed = processMeasureBatch(
                                    measureBatch,
                                    newEntityManager,
                                    detailIdToEffectIdMap,
                                    detailIdToConsequenceIdMap);

                            rowsProcessed.addAndGet(batchProcessed);
                            newEntityManager.getTransaction().commit();
                        } catch (Exception e) {
                            if (newEntityManager.getTransaction().isActive()) {
                                newEntityManager.getTransaction().rollback();
                            }
                            throw e;
                        } finally {
                            newEntityManager.close();
                            latch.countDown();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }

            // 等待所有任务完成
            waitForCompletion(latch, executorService);

        } catch (Exception e) {
            throw e;
        } finally {
            oldEntityManager.close();
        }

        return rowsProcessed.get();
    }

    /**
     * 处理措施批次数据
     */
    private int processMeasureBatch(
            List<RaFaultChainsMeasure> measureBatch,
            EntityManager newEntityManager,
            Map<Long, String> detailIdToEffectIdMap,
            Map<Long, String> detailIdToConsequenceIdMap) {

        List<Object> batchEntities = new ArrayList<>();

        // 处理每个措施关系
        for (RaFaultChainsMeasure measure : measureBatch) {
            Byte sourceType = measure.getSourceType();
            Byte measuresType = measure.getMeasuresType();
            Long linkedId = measure.getLinkedId();
            Long measuresId = measure.getMeasuresId();

            if (sourceType == 1) { // 影响节点相关措施
                // 从linkedId找到对应的detail，再获取influenceId作为effect_id
                String effectId = detailIdToEffectIdMap.get(linkedId);
                if (effectId == null) {
                    continue; // 如果找不到对应的effectId，跳过
                }

                if (measuresType == 1) { // 防护措施
                    // 创建事故链影响节点-防护措施实体
                    RiskChainEffectProtection protection = new RiskChainEffectProtection();
                    protection.setId(measure.getId());
                    protection.setEffectId(effectId);
                    protection.setProtectionId(measuresId);

                    // 措施有效性状态映射：0初始化、1有效、2手动有效、3无效
                    if (measure.getStatus() != null) {
                        protection.setEffectiveFlag(measure.getStatus() == 1 || measure.getStatus() == 2);
                        protection.setEvaluatedFlag(measure.getStatus() == 2);
                    } else {
                        protection.setEffectiveFlag(false);
                        protection.setEvaluatedFlag(false);
                    }

                    newEntityManager.persist(protection);
                    batchEntities.add(protection);
                } else if (measuresType == 2) { // 建议措施
                    // 创建事故链影响节点-建议措施实体
                    RiskChainEffectSuggestion suggestion = new RiskChainEffectSuggestion();
                    suggestion.setId(measure.getId());
                    suggestion.setEffectId(effectId);
                    suggestion.setSuggestionId(measuresId);

                    // 措施有效性状态映射：0初始化、1有效、2手动有效、3无效
                    if (measure.getStatus() != null) {
                        suggestion.setNecessaryFlag(measure.getStatus() == 1 || measure.getStatus() == 2);
                        suggestion.setEvaluatedFlag(measure.getStatus() == 2);
                    } else {
                        suggestion.setNecessaryFlag(false);
                        suggestion.setEvaluatedFlag(false);
                    }

                    newEntityManager.persist(suggestion);
                    batchEntities.add(suggestion);
                }
            } else if (sourceType == 2) { // 后果节点相关措施
                // 从linkedId找到对应的detail，再获取consequenceId
                String consequenceId = detailIdToConsequenceIdMap.get(linkedId);
                if (consequenceId == null) {
                    continue; // 如果找不到对应的consequenceId，跳过
                }

                if (measuresType == 1) { // 防护措施
                    // 创建事故链后果节点-防护措施实体
                    RiskChainConsequenceProtection protection = new RiskChainConsequenceProtection();
                    protection.setId(measure.getId());
                    protection.setConsequenceId(consequenceId);
                    protection.setProtectionId(measuresId);

                    // 措施有效性状态映射：0初始化、1有效、2手动有效、3无效
                    if (measure.getStatus() != null) {
                        protection.setEffectiveFlag(measure.getStatus() == 1 || measure.getStatus() == 2);
                        protection.setEvaluatedFlag(measure.getStatus() == 2);
                    } else {
                        protection.setEffectiveFlag(false);
                        protection.setEvaluatedFlag(false);
                    }

                    newEntityManager.persist(protection);
                    batchEntities.add(protection);
                }
                // 注意：后果节点没有建议措施表
            }
        }

        return batchEntities.size();
    }

    /**
     * 获取所有防护措施数据
     *
     * @param oldEntityManager 旧数据库实体管理器
     * @return 防护措施数据列表
     */
    private List<RaDefendMeasures> getDefendMeasures(EntityManager oldEntityManager) {
        CriteriaBuilder cb = oldEntityManager.getCriteriaBuilder();
        CriteriaQuery<RaDefendMeasures> cq = cb.createQuery(RaDefendMeasures.class);
        Root<RaDefendMeasures> root = cq.from(RaDefendMeasures.class);
        return oldEntityManager.createQuery(cq).getResultList();
    }

    /**
     * 获取所有建议措施数据
     *
     * @param oldEntityManager 旧数据库实体管理器
     * @return 建议措施数据列表
     */
    private List<RaAdviseMeasures> getAdviseMeasures(EntityManager oldEntityManager) {
        CriteriaBuilder cb = oldEntityManager.getCriteriaBuilder();
        CriteriaQuery<RaAdviseMeasures> cq = cb.createQuery(RaAdviseMeasures.class);
        Root<RaAdviseMeasures> root = cq.from(RaAdviseMeasures.class);
        cq.where(cb.equal(root.get("isDel"), (byte) 0));
        return oldEntityManager.createQuery(cq).getResultList();
    }
}
